﻿import { warnMessage } from '@/utils/message'
import { loadEnv } from '^/index'
import { storeToRefs } from 'pinia'
import { transformI18n } from '@/plugins/i18n'
import { useUserInfoStoreWithOut } from '@/store/storage/userInfoStore'
const { VITE_WEBSOCKET_WSS } = loadEnv()
const userInfoStore = useUserInfoStoreWithOut()
const { userInfo } = storeToRefs(userInfoStore)
interface socketType {
  websocket: any
  wssURL: string
  sendData: object | null
  lockReconnect: boolean
  reconnectTimer: any
  connectWebsocket: (url, agentData, successCallback, errCallback) => any
  createWebSocket: () => void
  initWebSocketEventHandler: () => any
  onWebsocketOpen: (e) => void
  onWebsocketMessage: (e) => void
  onWebsocketClose: (e) => void
  onWebsocketError: (e) => void
  closeWebsocket: () => void
  reconnect: () => void
  messageCallback: (e) => void
  errorCallback: (e) => void
  heartbeatCheck: {
    timeout: number
    isInit: boolean
    timeoutTimer: any
    serverTimeoutTimer: any
    reset: () => void
    stop: () => void
    start: () => void
  }
}

const socket: socketType = {
  // websocket实例
  websocket: null,
  // websocket链接地址
  wssURL: VITE_WEBSOCKET_WSS,
  // 发送给后台的数据
  sendData: null,
  // 是否执行重连（true:不执行；false:执行）
  lockReconnect: false,
  // 重连定时器
  reconnectTimer: null,
  // 获取后端数据成功的回调函数
  messageCallback: null,
  // 获取后端数据失败的回调函数
  errorCallback: null,
  /**
   * 发起websocket连接请求函数
   * @param {string} url ws连接地址
   * @param {Object} agentData 传给后台的参数
   * @param {function} successCallback 接收到ws数据，对数据进行处理的回调函数
   * @param {function} errCallback ws连接错误的回调函数
   */
  connectWebsocket: (url, agentData, successCallback, errCallback) => {
    socket.wssURL = socket.wssURL + url
    socket.sendData = agentData
    socket.createWebSocket()
    socket.messageCallback = successCallback
    socket.errorCallback = errCallback
  },
  // 创建ws链接函数
  createWebSocket: () => {
    if (!('WebSocket' in window)) {
      warnMessage(transformI18n('errors.errorDontSupportWebSocket', true))
      return null
    }
    try {
      // websocket实例化
      socket.websocket = new WebSocket(socket.wssURL)
      // 初始化websocket事件函数
      socket.initWebSocketEventHandler()
    } catch (e) {
      // 开始重连
      socket.reconnect()
    }
  },
  // 初始化websocket连接事件工具方法
  initWebSocketEventHandler: () => {
    try {
      // 连接成功
      socket.websocket.onopen = (event) => {
        socket.onWebsocketOpen(event)
        // 开启心跳检测
        socket.heartbeatCheck.start()
      }
      // 监听服务器端返回的信息
      socket.websocket.onmessage = (e: any) => {
        socket.onWebsocketMessage(e)
        // 开启心跳检测
        socket.heartbeatCheck.start()
      }
      // 执行关闭websocket通信事件
      socket.websocket.onclose = (e: any) => {
        socket.onWebsocketClose(e)
      }
      // 连接发生错误
      socket.websocket.onerror = function (e: any) {
        socket.onWebsocketError(e)
        socket.reconnect()
      }
    } catch (e) {
      // 执行websocket通信失败的回调函数
      socket.errorCallback(transformI18n('errors.socketFail1', true))
      socket.reconnect()
    }
  },
  // websocket进行连接
  onWebsocketOpen: () => {
    // 客户端与服务器端通信
    // socket.websocket.send('我发送消息给服务端');
    // 添加状态判断，当为OPEN时，发送消息
    if (socket.websocket.readyState === socket.websocket.OPEN) {
      // socket.websocket.OPEN = 1
      // 发给后端的数据需要字符串化
      socket.websocket.send(JSON.stringify(socket.sendData))
    }
    if (socket.websocket.readyState === socket.websocket.CLOSED) {
      // socket.websocket.CLOSED = 3
      // 执行websocket通信失败的回调函数
      socket.errorCallback(transformI18n('errors.socketFail2', true))
      // 开始进行重连
      socket.reconnect()
    }
  },
  // websocket监听服务器端返回消息
  onWebsocketMessage: (event) => {
    const jsonStr = event.data
    console.log('onWebsocketMessage: ', jsonStr)
    // 执行websocket通信成功的回调函数
    socket.messageCallback(jsonStr)
  },
  // websocket执行关闭事件
  onWebsocketClose: (event) => {
    // e.code === 1000  表示正常关闭。 无论为何目的而创建, 该链接都已成功完成任务。
    // e.code !== 1000  表示非正常关闭。
    console.log('onclose event: ', event)
    if (event && event.code !== 1000) {
      // 执行websocket通信失败的回调函数
      socket.errorCallback(transformI18n('errors.socketFail3', true))
      // 如果不是手动关闭，这里的重连会执行；如果调用了手动关闭函数，这里重连不会执行
      socket.reconnect()
    }
  },
  // websocket执行连接错误事件，
  onWebsocketError: (event) => {
    console.log('onWebsocketError：', event.data)
    // 执行websocket通信失败的回调函数
    socket.errorCallback(event.data)
  },
  // 手动关闭websocket
  closeWebsocket: () => {
    if (socket.websocket) {
      socket.websocket.close() // 关闭websocket
      // socket.websocket.onclose() // 关闭websocket(如果上面的关闭不生效就加上这一条)
      // 关闭重连
      socket.lockReconnect = true
      socket.reconnectTimer && clearTimeout(socket.reconnectTimer)
      // 关闭心跳检查
      socket.heartbeatCheck.stop()
    }
  },
  // 重新连接
  reconnect: () => {
    if (socket.lockReconnect) {
      socket.errorCallback(transformI18n('errors.socketFail4', true))
      return
    }
    socket.lockReconnect = true
    // 没连接上会一直重连，设置延迟避免请求过多
    socket.reconnectTimer && clearTimeout(socket.reconnectTimer)
    socket.reconnectTimer = setTimeout(() => {
      socket.errorCallback(transformI18n('errors.socketFail5', true))
      socket.createWebSocket()
      socket.lockReconnect = false
    }, 3000)
  },
  // 心跳检查，查看websocket是否还在正常链接中，心跳是用来测试链接是否存在和对方是否在线
  heartbeatCheck: {
    timeout: 15000,
    isInit: true,
    timeoutTimer: null,
    serverTimeoutTimer: null,
    // 重启
    reset: () => {
      clearTimeout(socket.heartbeatCheck.timeoutTimer)
      clearTimeout(socket.heartbeatCheck.serverTimeoutTimer)
      socket.heartbeatCheck.start()
    },
    // 停止
    stop: () => {
      clearTimeout(socket.heartbeatCheck.timeoutTimer)
      clearTimeout(socket.heartbeatCheck.serverTimeoutTimer)
    },
    // 开始
    start: () => {
      if (socket.heartbeatCheck.isInit) {
        socket.heartbeatCheck.isInit = false
        socket.heartbeatCheck.timeoutTimer && clearTimeout(socket.heartbeatCheck.timeoutTimer)
        socket.heartbeatCheck.serverTimeoutTimer && clearTimeout(socket.heartbeatCheck.serverTimeoutTimer)
        // 15s之内如果没有收到后台的消息，则认为是连接断开了，需要重连
        socket.heartbeatCheck.timeoutTimer = setTimeout(() => {
          socket.heartbeatCheck.isInit = true
          try {
            // 这里需要看后台程序需要的是什么类型数据字段，是否需要回传token，也需要看后台程序是否做了websocket发送ping帧的功能
            const data = {
              ping: true
            }
            socket.websocket.send(JSON.stringify(data))
          } catch (err) {
            console.log('ping error')
          }
          console.log('socket.heartbeatCheck.serverTimeoutTimer: ', socket.heartbeatCheck.serverTimeoutTimer)
          // 内嵌定时器
          socket.heartbeatCheck.serverTimeoutTimer = setTimeout(() => {
            socket.errorCallback(transformI18n('errors.socketFail6', true))
            socket.reconnect()
          }, socket.heartbeatCheck.timeout)
        }, socket.heartbeatCheck.timeout)
      }
    }
  }
}

export default socket
